﻿using System;

namespace GVPSys.sysbase
{
    internal interface ICommandExecutor
    {
        void Execute();
    }

    internal class CommandExecutor : ICommandExecutor
    {
        private readonly IInvocation invocation;
        private readonly ICommandAdvisor commandAdvisor;

        public CommandExecutor(IInvocation invocation, ICommandAdvisor commandAdvisor)
        {
            this.invocation = invocation;
            this.commandAdvisor = commandAdvisor;
        }

        void ICommandExecutor.Execute()
        {
            if (invocation == null)
                throw new Exception("invocation is null");

            if (commandAdvisor == null)
            {
                invocation.Proceed();
                return;
            }

            object result;
            try
            {
                CommandBefore();
                result = commandAdvisor.Interceptor != null
                    ? commandAdvisor.Interceptor.Invoke(invocation)
                    : invocation.Proceed();
            }
            catch (Exception err)
            {
                if (err is System.Reflection.TargetInvocationException)
                {
                    err = err.InnerException;
                }

                if (commandAdvisor.ExceptionInterceptors == null) throw;

                foreach (var errInterceptor in commandAdvisor.ExceptionInterceptors)
                {
                    errInterceptor.AfterThrowing(err);
                }
                return;
            }
            //执行完成
            CommandAfter(result);
        }

        private void CommandBefore()
        {
            if (commandAdvisor.Befores == null) return;
            foreach (var before in commandAdvisor.Befores)
            {
                before.Before(invocation.Parameter);
            }
        }

        private void CommandAfter(object result)
        {
            if (commandAdvisor.Afters == null) return;
            foreach (var after in commandAdvisor.Afters)
            {
                after.After(result);
            }
        }
    }
}